# StartTCL: n
#
# XPControl
#
# This program is (c) 2006 by Spirit <thehiddenspirit@hotmail.com>
#
# This program is free software; you can redistribute it and/or modify it under
# the terms of the GNU Lesser General Public License as published by the Free
# Software Foundation; either version 2.1 of the License, or (at your option)
# any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
# FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
# details.
#
# You should have received a copy of the GNU Lesser General Public License
# along with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. You can also consult
# the terms of the license at:
#
#		<http://www.gnu.org/copyleft/lesser.html>
#
# Description: controls XP from quests, mobs or map exploration
#

namespace eval ::XPControl {

	variable MAX_LEVEL default
	variable CONTROL_QUESTS 1
	variable CONTROL_MOBS 1
	variable CONTROL_EXPLORATION 1
	variable USE_MASTERSCRIPT 1

	variable Q_OFFSET 10000
	variable VERSION 0.25

	variable SCRIPTS_DIR "scripts"
	variable QUESTS_FILE "$SCRIPTS_DIR/quests.scp"
	variable QUESTS_NOXP_FILE "$SCRIPTS_DIR/quests_noxp.scp"

	variable DEBUG 0
	variable USE_CONF 1

	if { $USE_CONF } { ::Custom::LoadConf }

	if { ![string is integer -strict $MAX_LEVEL] } {
		set MAX_LEVEL [expr {[info exists ::WoWEmu::MAX_LEVEL] ? $::WoWEmu::MAX_LEVEL : 60}]
	}

	if { $CONTROL_QUESTS } {

		# generate "quests_noxp.scp" file, which is basically "quests.scp" with offset entries
		proc GenerateQuestsNoXP {} {
			variable QUESTS_FILE
			variable QUESTS_NOXP_FILE
			variable Q_OFFSET
			set count 0
			set total 0
			set wrong 0
			set include "#include $QUESTS_NOXP_FILE"
			set hquests [open $QUESTS_FILE]
			set hquests_noxp [open $QUESTS_NOXP_FILE w]
			while { [gets $hquests line] >= 0 } {
				if { $line == $include } { continue }
				if { [string index $line 0] == "\[" } {
					set wrong 0
					set section [lindex [split $line {[]}] 1]
					set type [lindex $section 0]
					if { $type == "quest" } {
						set qid [lindex $section 1]
						if { [string is integer -strict $qid] && $qid <= $Q_OFFSET } {
							incr qid $Q_OFFSET
							incr count
						} else {
							set wrong 1
							::Custom::Error "Can't offset by $Q_OFFSET in $QUESTS_FILE: $section"
						}
						set line "\[quest $qid\]"
					} else {
						set wrong 1
						::Custom::Error "Can't offset by $Q_OFFSET in $QUESTS_FILE: $section"
					}
					incr total
				} elseif { !$wrong } {
					set key [string trim [lindex [split $line "="] 0]]
					switch -- $key {
						"reward_xp" {
							# setting 0 gives 250xp...
							set line "$key=-1"
						}
						"next_quest" {
							set value [string trim [lindex [split $line "="] 1]]
							if { [string is integer -strict $value] && $value <= $Q_OFFSET } {
								incr value $Q_OFFSET
								set line "$key=$value"
							}
						}
						"requirements" {
							set requirements [string trim [lindex [split $line "="] 1]]
							set req_pos 0
							foreach elem $requirements {
								set elem [string tolower $elem]
								set rtype [string range $elem 0 0]
								if { $rtype == "!" } {
									set logop "!"
									set rtype [string range $elem 1 1]
									set elem [string range $elem 2 end]
								} else {
									set logop ""
									set elem [string range $elem 1 end]
								}
							    if { $rtype == "q" } {
								    set ps [split $elem |]
								    set i 0
								    foreach rq $ps {
									    if { [string is integer -strict $rq] } {
									    	incr rq $Q_OFFSET
									    	lset ps $i $rq
								    	}
								    	incr i
								    }
								    set elem [join $ps |]
								    lset requirements $req_pos $logop$rtype$elem
							    }
							    incr req_pos
							}
							set line "$key=$requirements"
						}
					}
				}
				if { !$wrong && [string range $line 0 1] != "//" } {
					puts $hquests_noxp $line
				}
			}
			close $hquests
			close $hquests_noxp
			list $count $total
		}

		# add "#include scripts/quests_noxp.scp" line to "quests.scp"
		proc AddInclude {} {
			variable QUESTS_FILE
			variable QUESTS_NOXP_FILE
			set include "#include $QUESTS_NOXP_FILE"
			set content {}
			set found_include 0
			set handle [open $QUESTS_FILE]
			while { [gets $handle line] >= 0 } {
				if { [string trim $line] == $include } { incr found_include }
				lappend content $line
			}
			close $handle
			if { !$found_include } {
				set count 0
				set added 0
				set handle [open $QUESTS_FILE w]
				foreach line $content {
					if { !$added && [string is ascii $line] && [string range [string trim $line] 0 1] != "//" } {
						if { !$count } { puts $handle "" }
						puts $handle $include
						if { [string trim $line] != "" } { puts $handle "" }
						set added 1
					}
					puts $handle $line
					incr count
				}
				close $handle
			}
			expr !$found_include
		}

		# check for "quests_noxp.scp" on startup
		if { ![file exists $QUESTS_NOXP_FILE] } {
			if { [lindex [set result [GenerateQuestsNoXP]] 0] } {
				AddInclude
				puts "\n[::Custom::LogPrefix]XPControl: \"$QUESTS_NOXP_FILE\" generated ([join $result /]), you need to \".rescp\".\n"
			} else {
				puts "\n[::Custom::LogPrefix]XPControl: \"$QUESTS_NOXP_FILE\" couldn't be generated.\n"
			}
		}
	}

	if { [::Custom::GetScriptVersion "StartTCL"] < "0.9.0" } {
		# control of xp from killing mobs or exploring maps

		if { $CONTROL_MOBS } {
			::Custom::ChainCmd "::WoWEmu::CalcXP" {
				if { [::GetLevel $killer] >= $::XPControl::MAX_LEVEL } {
					return 0
				}
				return $return
			}
		}

		if { $CONTROL_EXPLORATION } {
			::Custom::ChainCmd "::WoWEmu::ExplorationXP" {
				if { [::GetLevel $player] >= $::XPControl::MAX_LEVEL } {
					return 0
				}
				return $return
			}
		}
	}

	::StartTCL::Provide
}

if { $::XPControl::CONTROL_QUESTS } {

	if { $::XPControl::USE_MASTERSCRIPT } {
		# MasterScript specific control

		if { [::Custom::GetScriptVersion "StartTCL"] >= "0.9.0" } {
			::StartTCL::Require MasterScript
		}

		if { [info procs "::MasterScript::GetStartableQuests"] != "" } {

			set ::MasterScript::XPControl_PlayerLevel 1

			# add a temporary variable so we can know the player's level from GetScpValue
			foreach proc {GetStartableQuests GetFinishableQuests} {
				::Custom::HookProc ::MasterScript::$proc {
					variable XPControl_PlayerLevel [::GetLevel $player]
				}
			}

			proc ::MasterScript::GetScpValue { scpfile section key } {
				variable GetScpValue
				variable XPControl_PlayerLevel

				set max [expr {$XPControl_PlayerLevel >= $::XPControl::MAX_LEVEL}]
				if { ![info exists GetScpValue($scpfile,$section,$key,$max)] } {
					set value [::GetScpValue $scpfile $section $key]
					if { $max } {
						if { [lsearch "finishes_quests starts_quests startquest sound1" $key] >= 0 } {
							for { set i 0 } { $i < [llength $value] } { incr i } {
								for { set j 0 } { $j < [llength [lindex $value $i]] } { incr j } {
									lset value $i $j [expr {[lindex $value $i $j] + $::XPControl::Q_OFFSET}]
								}
							}
						}
					}
					set GetScpValue($scpfile,$section,$key,$max) $value
				}
				return $GetScpValue($scpfile,$section,$key,$max)
			}

			foreach proc {GetQFlag SetQFlag} {
				eval "proc ::MasterScript::$proc \{ player flag \} \{
					if \{ \[GetLevel \$player\] >= \$::XPControl::MAX_LEVEL \} \{
						set questid \[string range \$flag 1 end\]
						if \{ \$questid > \$::XPControl::Q_OFFSET \} \{ incr questid -\$::XPControl::Q_OFFSET \}
						set flag Q\$questid
					\}
					::$proc \$player \$flag
				\}"
			}

		}
	} else {
		# generic control (For original, Neo2003's or other quest systems)

		rename GetQuestStatus Wad::GetQuestStatus
		proc GetQuestStatus { player questid args } {
			if { [GetLevel $player] >= $::XPControl::MAX_LEVEL } { if { $questid < $::XPControl::Q_OFFSET } { incr questid $::XPControl::Q_OFFSET } }
			Wad::GetQuestStatus $player $questid
		}

		rename GetQFlag Wad::GetQFlag
		proc GetQFlag { player flag args } {
			if { [GetLevel $player] >= $::XPControl::MAX_LEVEL } {
				if { [string index $flag 0] == "Q" && [string is integer -strict [set questid [string range $flag 1 end]]] } {
					if { $questid > $::XPControl::Q_OFFSET } { incr questid -$::XPControl::Q_OFFSET }
					set flag "Q$questid"
				}
			}
			Wad::GetQFlag $player $flag
		}

		rename SetQFlag Wad::SetQFlag
		proc SetQFlag { player flag args } {
			if { [GetLevel $player] >= $::XPControl::MAX_LEVEL } {
				if { [string index $flag 0] == "Q" && [string is integer -strict [set questid [string range $flag 1 end]]] } {
					if { $questid > $::XPControl::Q_OFFSET } { incr questid -$::XPControl::Q_OFFSET }
					set flag "Q$questid"
				}
			}
			Wad::SetQFlag $player $flag
		}

		rename ClearQFlag Wad::ClearQFlag
		proc ClearQFlag { player flag args } {
			if { [GetLevel $player] >= $::XPControl::MAX_LEVEL } {
				if { [string index $flag 0] == "Q" && [string is integer -strict [set questid [string range $flag 1 end]]] } {
					if { $questid > $::XPControl::Q_OFFSET } { incr questid -$::XPControl::Q_OFFSET }
					set flag "Q$questid"
				}
			}
			Wad::ClearQFlag $player $flag
		}

		rename SendQuestDetails Wad::SendQuestDetails
		proc SendQuestDetails { player npc qid {qname ""} {qdesc ""} {qdetails ""} args } {
			if { [GetLevel $player] >= $::XPControl::MAX_LEVEL } { if { $qid < $::XPControl::Q_OFFSET } { incr qid $::XPControl::Q_OFFSET } }
			Wad::SendQuestDetails $player $npc $qid $qname $qdesc $qdetails
		}

		rename SendQuestsList Wad::SendQuestsList
		proc SendQuestsList { player npc {args ""} } {
			set newargs $args
			if { [GetLevel $player] >= $::XPControl::MAX_LEVEL } {
				set newargs {}
				foreach arg $args {
					if { [string is integer -strict $arg] } {
						lappend newargs [expr {$arg+$::XPControl::Q_OFFSET}]
					}
				}
			}
			eval "Wad::SendQuestsList $player $npc $newargs"
		}

		rename SendQuestRequestItems Wad::SendQuestRequestItems
		proc SendQuestRequestItems { player npc qid {qname ""} {qdesc ""} args } {
			if { [GetLevel $player] >= $::XPControl::MAX_LEVEL } { if { $qid < $::XPControl::Q_OFFSET } { incr qid $::XPControl::Q_OFFSET } }
			Wad::SendQuestRequestItems $player $npc $qid $qname $qdesc
		}

		rename SendQuestComplete Wad::SendQuestComplete
		proc SendQuestComplete { player questid args } {
			if { [GetLevel $player] >= $::XPControl::MAX_LEVEL } { if { $questid < $::XPControl::Q_OFFSET } { incr questid $::XPControl::Q_OFFSET } }
			Wad::SendQuestComplete $player $questid
		}

		rename SendQuestReward Wad::SendQuestReward
		proc SendQuestReward { player npc qid {qname ""} {qdesc ""} args } {
			if { [GetLevel $player] >= $::XPControl::MAX_LEVEL } { if { $qid < $::XPControl::Q_OFFSET } { incr qid $::XPControl::Q_OFFSET } }
			Wad::SendQuestReward $player $npc $qid $qname $qdesc
		}

	}

}



if { $::XPControl::DEBUG } {
	foreach cmd {
		GetQuestStatus GetQFlag SetQFlag ClearQFlag SendQuestDetails SendQuestsList\
		SendQuestRequestItems SendQuestComplete SendQuestReward
	} {
		Custom::TraceCmd $cmd 1
	}
}

